package elitequant.data;

import static elitequant.util.UtilFunc.getTodayFormat;
import static elitequant.util.UtilFunc.parseDate;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.json.JSONArray;
import org.json.JSONObject;

import elitequant.util.UtilFunc;

/**
 * BacktestDataFeed retrieves historical data; which is pulled out by
 * backtest_event_engine.
 *
 */
public class BacktestDataFeedTushare extends DataFeedBase {
    
    private final static String IFENG_API = "http://api.finance.ifeng.com/akdaily/?code=%s&type=last";

    private String startDate;
    private String endDate;
    private List<BarEvent> histData;
    private Iterator<BarEvent> dataStream;

    public BacktestDataFeedTushare(String startDate, String endDate) {

        if (endDate != null) {
            this.endDate = endDate;
        } else {
            this.endDate = getTodayFormat();
        }

        if (startDate != null) {
            this.startDate = startDate;
        } else {
            this.startDate = UtilFunc.getLaterFormat(-365);
        }

        histData = new ArrayList<BarEvent>();
    }

    @Override
    public void subscribeMarketData(String[] symbols) {
        if(symbols != null) {
            for(String sym : symbols) {
                retrieveOnlineHistoricalData(sym);
            }
        }
        
        // order by
        histData.sort((bar1, bar2) -> {
            return bar1.barStartTime.compareTo(bar2.barStartTime);
        });
        
        dataStream = histData.iterator();

    }

    @Override
    public void unsubscribeMarketData(String[] symbols) {

    }

    @Override
    public BarEvent streamNext() {
        if(dataStream.hasNext()) {
            return dataStream.next();
        }
        else {
            return null;
        }
    }
    
    /**
     * get_hist_data of tushare(1.0.3)
     * 
     * @param symbol
     * @param start
     * @param end
     */
    private void retrieveOnlineHistoricalData(String code) {
        Date start = parseDate(startDate);
        Date end = parseDate(endDate);
        
        String symbol = codeToSymbol(code);
        String url = String.format(IFENG_API, symbol);
        String json = httpGet(url);
        JSONObject obj = new JSONObject(json);
        JSONArray record = obj.getJSONArray("record");
        
        for (int i = 0; i < record.length(); i++) {
            JSONArray item = record.getJSONArray(i);
            
            // filter data 
            Date date = UtilFunc.parseDate(item.getString(0));
            if((start != null && date.compareTo(start) < 0) 
                    || (end != null && date.compareTo(end) > 0)){
                continue;
            }
            
            BarEvent bar = new BarEvent();
            bar.fullSymbol = symbol;
            bar.interval = 86400;
            bar.barStartTime = UtilFunc.parseDate(item.getString(0));
            bar.openPrice = new BigDecimal(item.getString(1));
            bar.highPrice = new BigDecimal(item.getString(2));
            bar.closePrice = new BigDecimal(item.getString(3));
            bar.adjClosePrice = new BigDecimal(item.getString(3));
            bar.lowPrice = new BigDecimal(item.getString(4));
            bar.volume = new BigDecimal(item.getString(5)).intValue();
            histData.add(bar);
        }
    }

    /*
     * 生成symbol代码标志
     */
    private String codeToSymbol(String code) {
        if (INDEX_LABELS.contains(code)) {
            return INDEX_LIST.get(code);
        } else {
            if (code.trim().length() != 6) {
                return code;
            } else {
                boolean isSh = code.charAt(0) == '5' || code.charAt(0) == '6'
                        || code.charAt(0) == '9';
                return String.format("%s%s", isSh ? "sh" : "sz", code);
            }
        }
    }

    private final static Set<String> INDEX_LABELS = new HashSet<String>() {
        {
            add("sh");
            add("sz");
            add("hs300");
            add("sz50");
            add("cyb");
            add("zxb");
            add("zx300");
            add("zh500");
        }
    };
    private final static Map<String, String> INDEX_LIST = new HashMap<String, String>() {
        {
            put("sh", "sh000001");
            put("sz", "sz399001");
            put("hs300", "sh000001");
            put("sz50", "sh000016");
            put("zxb", "sz399005");
            put("cyb", "sz399006");
            put("zx300", "sz399008");
            put("zh500", "sh000905");
        }
    };

}
